/*
 * Copyright (C) 2018 xuexiangjys(xuexiangjys@163.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.xuexiang.xdlink.component.channel.impl;

import com.xuexiang.xdlink.component.channel.IChannel;
import com.xuexiang.xdlink.component.channel.IDataReceiver;
import com.xuexiang.xdlink.component.channel.OnChannelListener;
import com.xuexiang.xdlink.component.channel.entity.ConnectStatusEnum;
import com.xuexiang.xdlink.logs.DCFLog;

/**
 * 抽象的通信通道
 *
 * @author xuexiang
 * @since 2018/8/13 下午11:27
 */
public abstract class AbstractChannel implements IChannel {
    /**
     * 通信通道监听
     */
    private OnChannelListener mOnChannelListener;
    /**
     * 通信通道的状态
     */
    private ConnectStatusEnum mConnectStatus;
    /**
     * 通信通道是否打开
     */
    private volatile boolean mIsOpened = false;

    /**
     * 重新打开通道的次数
     */
    private int mReopenCount = 0;

    private IDataReceiver mIDataReceiver;

    @Override
    public boolean isOpen() {
        return mIsOpened;
    }

    @Override
    public void reOpenChannel() {
        mReopenCount++;
    }

    @Override
    public int getReOpenCount() {
        return mReopenCount;
    }

    @Override
    public void setOnChannelListener(OnChannelListener listener) {
        mOnChannelListener = listener;
    }

    protected OnChannelListener getChannelListener() {
        return mOnChannelListener;
    }

    /**
     * @return 获取通道连接状态
     */
    @Override
    public ConnectStatusEnum getConnectStatus() {
        return mConnectStatus;
    }

    /**
     * 更新通信通道的连接状态
     *
     * @param status 状态
     */
    protected void updateConnectStatus(ConnectStatusEnum status) {
        switch (status) {
            case CONNECT_SUCCESS:
            case ALREADY_CONNECTED:
            case RECONNECT_SUCCESS:
                updateOpenedStatus(true);
                mReopenCount = 0;
                break;
            case CONNECT_FAILED:
            case RECONNECT_FAILED:
                updateOpenedStatus(false);
                break;
            case DISCONNECT_SUCCESS:
                updateOpenedStatus(false);
                mReopenCount = 0;
                break;
            default:
                break;
        }
        mConnectStatus = status;
        if (mOnChannelListener != null) {
            DCFLog.i("Channel connect status has changed， connect status：" + mConnectStatus);
            mOnChannelListener.onConnectStatusChanged(this);
        }
    }

    /**
     * 更新通道打开的状态
     * @param isOpened
     */
    protected void updateOpenedStatus(boolean isOpened) {
        mIsOpened = isOpened;
    }

    /**
     * 开始接收数据
     *
     * @param dataReceiver 数据接收器
     */
    protected void startAcceptData(IDataReceiver dataReceiver) {
        if (dataReceiver != null) {
            mIDataReceiver = dataReceiver;
            mIDataReceiver.startWork();
        }
    }

    /**
     * 停止接收数据
     */
    protected void stopAcceptData() {
        if (mIDataReceiver != null) {
            mIDataReceiver.finishWork();
            mIDataReceiver = null;
        }
    }

    /**
     * 通道接收到数据
     *
     * @param channel
     * @param data
     * @param available
     */
    protected void onDataReceived(IChannel channel, byte[] data, int available) {
        if (mOnChannelListener != null) {
            mOnChannelListener.onDataReceived(channel, data, available);
        }
    }

    @Override
    public String toString() {
        return getClass().getSimpleName();
    }

    /**
     * 关闭数据通道连接
     */
    protected void close() {
        DCFLog.i(toString() + " is closing...");
        stopAcceptData();
        updateOpenedStatus(false);
        mOnChannelListener = null;
    }
}
